package org.nudt.common.config

import cn.dev33.satoken.context.SaHolder
import cn.dev33.satoken.filter.SaServletFilter
import cn.dev33.satoken.`fun`.SaParamFunction
import cn.dev33.satoken.interceptor.SaInterceptor
import cn.dev33.satoken.router.SaRouter
import cn.dev33.satoken.router.SaRouterStaff
import cn.dev33.satoken.util.SaResult
import org.slf4j.LoggerFactory
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.web.servlet.config.annotation.InterceptorRegistry
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer


@Configuration
class SaTokenConfigure : WebMvcConfigurer {
    
    var log = LoggerFactory.getLogger(SaTokenConfigure::class.java)
    
    // 注册 Sa-Token 拦截器，打开注解式鉴权功能
    override fun addInterceptors(registry: InterceptorRegistry) {
        // 注册 Sa-Token 拦截器，打开注解式鉴权功能
        // 这里通过 registry.addInterceptor(SaInterceptor()) 方法注册了一个 Sa-Token 拦截器
        // addPathPatterns("/**") 表示该拦截器将拦截所有路径
        registry.addInterceptor(SaInterceptor {
            // SaManager.getLog().debug("----- 请求path={}  提交token={}", SaHolder.getRequest().getRequestPath(), StpUtil.getTokenValue());
            
            // 权限校验 -- 不同模块认证不同权限
            // SaRouter.match("/admin/**") { r: SaRouterStaff? -> StpUtil.checkPermission("admin") }
            
            // 甚至你可以随意的写一个打印语句
            // SaRouter.match("/v1/**") { r: SaRouterStaff? -> log.info("----啦啦啦2----") }
            
        }).addPathPatterns("/**")
    }
    
    @Bean
    fun getSaServletFilter(): SaServletFilter {
        return SaServletFilter() // 指定 [拦截路由] 与 [放行路由]
            
            .addInclude("/**") // .addExclude("/favicon.ico")
            // 认证函数: 每次请求执行
            
            .setAuth { obj: Any? ->
                // System.out.println("---------- sa全局认证 " + SaHolder.getRequest().getRequestPath());
                // SaManager.getLog().debug("----- 请求path={}  提交token={}", SaHolder.getRequest().getRequestPath(), StpUtil.getTokenValue());
                
                // 权限校验 -- 不同模块认证不同权限
                //		这里你可以写和拦截器鉴权同样的代码，不同点在于：
                // 		校验失败后不会进入全局异常组件，而是进入下面的 .setError 函数
                // SaRouter.match("/admin/**") { r: SaRouterStaff? -> StpUtil.checkPermission("admin") }
            } // 异常处理函数：每次认证函数发生异常时执行此函数
            
            .setError { e: Throwable ->
                log.info("---------- sa全局异常 ")
                SaResult.error(e.message)
            } // 前置函数：在每次认证函数之前执行（BeforeAuth 不受 includeList 与 excludeList 的限制，所有请求都会进入）
            
            .setBeforeAuth { r: Any? ->
                // ---------- 设置一些安全响应头 ----------
                SaHolder.getResponse() // 服务器名称
                    .setServer("sa-server") // 是否可以在iframe显示视图： DENY=不可以 | SAMEORIGIN=同域下可以 | ALLOW-FROM uri=指定域名下可以
                    .setHeader("X-Frame-Options", "SAMEORIGIN") // 是否启用浏览器默认XSS防护： 0=禁用 | 1=启用 | 1; mode=block 启用, 并在检查到XSS攻击时，停止渲染页面
                    .setHeader("X-XSS-Protection", "1; mode=block") // 禁用浏览器内容嗅探
                    .setHeader("X-Content-Type-Options", "nosniff")
                    .setHeader("Access-Control-Allow-Origin", "*")
                    .setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE")
                    .setHeader("Access-Control-Max-Age", "3600")
                    .setHeader("Access-Control-Allow-Headers", "*")
            }
    }
}